package org.longteng.mobileluck.orc.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baidu.aip.ocr.AipOcr;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.longteng.core.utils.StringExUtils;
import org.longteng.mobileluck.orc.service.ImageToTextApiCount;
import org.longteng.mobileluck.orc.service.ImageToTextService;
import org.longteng.mobileluck.orc.vo.OrcApiCount;
import org.longteng.mobileluck.orc.vo.OrcMobileNumResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * 图片识别文字,baidu api实现
 * @author hymn.com
 */
@Slf4j
@Service(value = "imageToTextBaiduOrc")
public class ImageToTextServiceBaiduImpl implements ImageToTextService {
    private static final String API_TYPE = "baidu";
    private static final long API_BASE_COUNT_MAX = 1000;      // 最大免费次数
    private static final long API_GENERAL_COUNT_MAX = 1000;   // 最大免费次数

    // 设置APPID/AK/SK
    @Value("${app.orc.baidu.app-id:29789000}")
    private String appId = "29789000";
    @Value("${app.orc.baidu.app-key:B3G12OCSfCjHblLDPXXXXXXXX}")
    private String apiKey = "B3G12OCSfCjHblLDPXXXXXXXX";
    @Value("${app.orc.baidu.secret-key:nwdDURNEXX5VGHhmoXX6HebXl4XXXXXX}")
    private String secretKey = "nwdDURNEXX5VGHhmoXX6HebXl4XXXXXX";


    @Autowired(required = false)
    private ImageToTextApiCount imageToTextApiCount;

    @PostConstruct
    public void init() {
        if (imageToTextApiCount == null) {
            log.info("未注入orc的API调用统计基础DB或redis实现,用基础默认实现ConcurrentHashMap版。");
            this.imageToTextApiCount = new ImageToTextApiCountBase();
        }
    }

    /**
     * baidu图片识别文字
     * @param imagePath
     * @param numType 号码类型
     * @return
     */
    @Override
    public OrcMobileNumResult toTextParseMobileNum(String imagePath, NumType numType) {
        if(log.isDebugEnabled()) {
            log.debug("baidu图片识别文字,图片文件：{}", imagePath);
        }
        OrcMobileNumResult orcMobileNumResult = null;
        try {
            byte[] imageBytes = FileUtils.readFileToByteArray(new File(imagePath));
            orcMobileNumResult = this.toTextParseMobileNum(imageBytes, numType);
        } catch (IOException e) {
            log.error("baidu图片识别文字,图片文件导入错误：{}", imagePath,e);
        }

        return orcMobileNumResult;
    }

    /**
     * 图片识别文字
     *
     * @param imageBytes 图片字节流
     * @param numType 号码类型
     * @return
     */
    @Override
    public OrcMobileNumResult toTextParseMobileNum(byte[] imageBytes, NumType numType) {
        OrcMobileNumResult orcMobileNumResult = new OrcMobileNumResult();
        List<String> result = new ArrayList<>();
        OrcApiCount orcApiCount = imageToTextApiCount.getOrcApiCount(API_TYPE);
        int countStatus = this.checkOrcApiCountOverflow(orcApiCount);
        orcMobileNumResult.setCountStatus(countStatus);
        if (countStatus >= 2 ) {
            log.error("【{}】ORC接口调用统计已超过免费次数,本月不可再免费用不用.", API_TYPE);
            return orcMobileNumResult;
        }

        try {
            // 初始化一个AipOcr
            AipOcr client = new AipOcr(appId, apiKey, secretKey);

            // 可选：设置网络连接参数
            client.setConnectionTimeoutInMillis(2000);
            client.setSocketTimeoutInMillis(60000);

            // 可选：设置代理服务器地址, http和socket二选一，或者均不设置
            // client.setHttpProxy("proxy_host", proxy_port); // 设置http代理
            // client.setSocketProxy("proxy_host", proxy_port); // 设置socket代理

            // 可选：设置log4j日志输出格式，若不设置，则使用默认配置
            // 也可以直接通过jvm启动参数设置此环境变量
            // System.setProperty("aip.log4j.conf", "path/to/your/log4j.properties");

            // 传入可选参数调用接口
            HashMap<String, String> options = new HashMap<String, String>();
            options.put("language_type", "CHN_ENG");  // 识别语言类型，默认为CHN_ENG
            options.put("detect_direction", "true");  // 是否检测图像朝向，默认不检测，即：false
            options.put("detect_language", "false");  // 是否检测语言，默认不检测。当前支持（中文、英语、日语、韩语）
            options.put("probability", "false");       // 是否返回识别结果中每一行的置信度

            // 本地图片路径或者图片二进制数据，先用基本的通用接口，用完再用带位置的通用接口
            JSONObject res = countStatus == 0
                    ? client.basicGeneral(imageBytes, options)
                    : client.general(imageBytes, options);

            int errorCode = res.has("error_code") ? res.getInt("error_code") : 0;
            if(log.isDebugEnabled()) {
                log.debug("图片转换,errorCode:{},转出的文字:{}", errorCode, res.toString(2)); // 转换的文字
            }
            if (errorCode > 2 ) {
                orcMobileNumResult.setCountStatus(errorCode);
                log.error("【{}】ORC接口调用发生错误：{}.", errorCode, API_TYPE);
                return orcMobileNumResult;
            }

            imageToTextApiCount.updateOrcApiCount(orcApiCount);   // 更新统计的调用次数

            // 通用文字识别, 图片参数为远程url图片
            // JSONObject res = client.basicGeneralUrl(url, options);

            // 提取文字
            // 获取到json数组
            org.json.JSONArray jsonArray = res.getJSONArray("words_result");
            // 创建一个字符串容器
            // StringBuffer sb = new StringBuffer();
            Iterator iterator = jsonArray.iterator();
            String word = null;
            while (iterator.hasNext()) {
                JSONObject type = (JSONObject) iterator.next();
                word = type.getString("words");
                // sb.append(word).append('\n');
                if (numType == NumType.MOBILE) {
                    this.parseCutMobileNum(word, result);
                } else {
                    if (this.isCartNum(word)) {
                        result.add(word);  // 车牌号直接加入
                    }
                }
            }
        } catch (Exception e) {
            log.error("baidu图片识别文字错误。", e);
        }
        orcMobileNumResult.setMobileNums(result);
        return orcMobileNumResult;
    }

    /**
     * 是否车牌号
     * @param word
     * @return
     */
    private boolean isCartNum(String word) {
        boolean result = false;
        int len = StringExUtils.length(word);
        // Regex regex = new Regex("[0-9]+");  // 字符串是否含有数字,汉字数少于2
        result = len>=6 && len<=8 && StringExUtils.countNumber(word)>0 && StringExUtils.countChinese(word)<2;

        return result;
    }

    /**
     * 数字-电话号码切分加到list
     * @param word
     * @param outMobileList
     */
    private void parseCutMobileNum(String word, List<String> outMobileList) {
        if (outMobileList != null && StringUtils.isNotBlank(word)) {
            String mobileWord = StringExUtils.parseMobileNumTrimReplace(word);
            if(StringUtils.isNumeric(mobileWord)) {
                if(mobileWord.length() > 11) {
                    String[] cut = StrUtil.cut(mobileWord, 11); // 按照长度切分字符串
                    outMobileList.addAll(Arrays.asList(cut));
                } else {
                    outMobileList.add(mobileWord);
                }
            } else {
                log.warn("不是数字的过滤：{}", mobileWord);
            }
        } else {
            log.warn("parseCutMobileNum(),要处理的文字或手机号列表为null。");
        }
    }

    /**
     * 检查调用次数是否溢出，无时加次数
     * @param orcApiCount
     * @return 0：正常，1：超次数，2：双接口都超次
     */
    private int checkOrcApiCountOverflow(OrcApiCount orcApiCount) {
        int result = 0;
        if(orcApiCount != null) {
            if(orcApiCount.getBaseCount() < API_BASE_COUNT_MAX) {
                orcApiCount.addBaseCount();
            } else {
                result = 1;
                log.warn("【{}】通用ORC接口调用统计已超过免费次数：{}", API_TYPE, API_BASE_COUNT_MAX);
                if(orcApiCount.getGeneralCount() < API_GENERAL_COUNT_MAX) {
                    orcApiCount.addGeneralCount();
                } else {
                    result = 2;
                    log.warn("【{}】通用(带位置)ORC接口调用统计已超过免费次数：{}", API_TYPE, API_GENERAL_COUNT_MAX);
                }
            }
            if(log.isDebugEnabled()) {
                log.debug("免费通用接口当月已使用次数为：基本：{}，通用(带位置)：{}", orcApiCount.getBaseCount(), orcApiCount.getGeneralCount());
            }
        } else {
            log.error("checkOrcApiCountOverflow(),传入参数为null");
        }
        return result;
    }

}
